﻿using System;
using System.Collections.Generic;
using System.Security.Policy;
using System.Web;
using System.Web.Mvc;
using System.Linq;

namespace Super.Common.Validate
{
    /// <summary> 数据验证助手
    /// </summary>
    public static class ValidateHelper
    {
        static ValidateHelper()
        {
            AllValidateRulesList = new Dictionary<string, List<ValidateRules>>();
        }

        /// <summary> 所有页面的所有验证规则 
        /// 现在由前端Validate对象自动生成, 将来项目发布后,由配置直接获取. 
        /// </summary>
        public static Dictionary<string, List<ValidateRules>> AllValidateRulesList { get; private set; }

        /// <summary> 从Url格式化为PageKey
        /// </summary> 
        /// <returns></returns>
        private static string UrlToPageKey(string tagerUrl)
        {
            //====test data=====
            //http://www.bangke.cn/ask/help?a=1
            //ask/help?b=2
            // /ask/help?c=3 
            // testAction?d=4 



            //生成Path
            if (tagerUrl == null)
            {
                tagerUrl = HttpContext.Current.Request.Path;
            }
            else
            {
                //remove http
                if (tagerUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
                {
                    tagerUrl = tagerUrl.Substring(tagerUrl.Substring(7).IndexOf("/") + 7);
                }
                else
                {

                    if (!tagerUrl.StartsWith("/"))
                    {
                        if (tagerUrl.IndexOf("/") > 0)
                        {
                            //规范的urlpath
                            tagerUrl = "/" + tagerUrl;
                        }
                        else
                        {
                            //需要计算的urlPath (替换最后一个节点)
                            var p = HttpContext.Current.Request.Path;
                            tagerUrl = p.Remove(p.LastIndexOf("/", StringComparison.Ordinal)) + "/" + tagerUrl;
                        }
                    }
                }
            }

            //移除掉参数部分.
            var v = tagerUrl.IndexOf("?");
            if (v > 0)
            {
                tagerUrl = tagerUrl.Remove(v);
            }

            //移除掉Params 部分.
            var llv = tagerUrl.Split('/').ToList();

            var lv = llv[llv.Count - 1];

            var l = llv.Count;

            if (lv == "" || ParamDic.CheckParam(lv))
            {
                l--;
            }

            var s = "";
            for (var i = 0; i < l; i++)
            {
                s += llv[i] + "/";
            }

            return s;
        }

        /// <summary> 当前页面的所有验证规则集合
        /// </summary>
        private static List<ValidateRules> GetPageValidateRulesList(bool isAutoAdd, string tagerUrl = null)
        {
            var urlKey = UrlToPageKey(tagerUrl);

            lock (AllValidateRulesList)
            {
                return AllValidateRulesList.ContainsKey(urlKey) ? AllValidateRulesList[urlKey] : (isAutoAdd ? (AllValidateRulesList[urlKey] = new List<ValidateRules>()) : null);
            }
        }

        /// <summary> 基于会话的数据验证Keys
        /// </summary>
        public static SessionData<int, List<ValidateRules>> UserValidateList
        {
            get
            {
                //基于会话的数据验证. 使用后 或者 20分 钟过期.
                return new SessionData<int, List<ValidateRules>>("UserValidateList", TimeSpan.FromMinutes(20));
            }
        }

        /// <summary> 验证表单,如果错误输出提示信息 ,忽略验证的控件用“,”分割
        /// </summary>
        /// <param name="c">当前控制器(this)</param>
        /// <param name="notCheckControlls">可选参数,可以对当前页面验证规则中控件忽略</param>
        /// <returns>true,验证通过</returns>
        public static bool CheckForm(Controller c, string notCheckControlls = "")
        {
            string s = string.Empty;

            if (CheckAll(notCheckControlls))
            {
                //有验证已经通过，输出信息
                c.ViewData["PageValidateMessage"] = PageMessage.ShowPageTips(s.Replace("\r\n", "<br/>"), "alert");
                return true;
            }
            else
            {
                //有验证没通过，输出信息
                c.ViewData["PageValidateMessage"] = PageMessage.ShowPageTips(s.Replace("\r\n", "<br/>"), "error");
                return false;
            }
        }


        /// <summary> 检查结果
        /// </summary>
        public static string CheckResult
        {
            get { return DataCache.HttpContextCache["ValidateCheckResult"].ToString(); }
            private set { DataCache.HttpContextCache["ValidateCheckResult"] = value; }
        }

        ///<summary> 当前验证规则缓存,用于恢复Key.
        /// </summary>
        private static List<ValidateRules> TempNowValidateRules { get { return DataCache.HttpContextCache["__nvl"] as List<ValidateRules>; } set { DataCache.HttpContextCache["__nvl"] = value; } }

        /// <summary> 验证表单  忽略验证的控件用“,”分割
        /// </summary> 
        /// <param name="notCheckControls">不检查的Control</param>
        /// <returns></returns>
        public static bool CheckAll(string notCheckControls = "")
        {
            //error = "";
            //return true; 

#if DEBUG
            if (HttpContext.Current.Request.Form["__ValidateKey"].IndexOf(",") > 0)
            {
                throw new Exception("重复的ValidateKey!");
            }
#endif

            //防重复提交
            var vKey = HttpContext.Current.Request.Form["__ValidateKey"].ToInt(0);

            string checkResult;

            if (UserValidateList.ContainsKey(vKey))
            {
#if DEBUG
                //checkAll 取的永远只能是自己的规则,而不可以取来路的规则.
                var nvl = GetPageValidateRulesList(false);

                if (nvl == null)
                {
                    throw new Exception("页面验证规则缺失.需要在Form中第一行增加Validate.CreateKey(Url).\r\n By:承志.");
                }

                //检查终结点规则 和 来路规则是否一致.
                if (nvl != UserValidateList[vKey])
                {
                    throw new Exception("严格验证发现问题:页面规则和来路规则发生冲突.\r\n这很可能是来自于一个攻击.如果不是,请联系我.\r\n By:承志.");
                }

                //禁止提交 Debug 下 先验证
                if (vKey > 0)
                    // < 0 的 key是非一次性的.
                    UserValidateList.Remove(vKey);
#else
                //禁止提交 Release 下 先移除 vKey
                if (vKey > 0) 
                    // < 0 的 key是非一次性的.
                    UserValidateList.Remove(vKey); 
                
                var nvl = GetPageValidateRulesList(false); 
#endif
                TempNowValidateRules = nvl;

                var sb = new System.Text.StringBuilder();
                var isOk = true;

                if (nvl.Count == 0)
                {
                    throw new Exception("未找到验证规则! 无法验证. By:承志");
                }

                foreach (var item in nvl)
                {
                    //忽略验证控件.
                    var ncc = notCheckControls.Split(',').Select(j => j.Trim().ToUpper()).ToArray();
                    if (ncc.Contains(item.ControlName.ToUpper()))   //后端不验证的控件
                        break;

                    if (!item.Check(out checkResult))
                    {
                        //输出错误内容. 
                        sb.AppendLine(item.ControlName + ":" + checkResult);
                        isOk = false;
                    }
                }
                checkResult = sb.ToString();

                if (isOk)
                    checkResult = "验证通过";
                else
                    //恢复Key
                    UserValidateList[vKey] = nvl;

                Log.FileLog.Write(checkResult + "({0})".FormatMe(vKey), LogType.Hint);

                CheckResult = checkResult;
                return isOk;
            }
            else
            {
                checkResult = "数据重复提交,请按F5刷新页面重试.";
                Log.FileLog.Write(checkResult + "({0})".FormatMe(vKey), LogType.Info);
                CheckResult = checkResult;
                return false;
            }
        }

        private static readonly Random _rd = new Random((int)DateTime.Now.Ticks);

        /// <summary> 在内存中生成一个ValidateKey 并返回.
        /// </summary>
        /// <param name="isOneTime"> </param>
        /// <param name="urlTager"></param>
        /// <returns></returns>
        internal static int CreateKey(bool isOneTime, string urlTager = null)
        {
            //一次性为正数,非一次性为负数.
            var k = isOneTime ? _rd.Next(1, int.MaxValue) : _rd.Next(int.MinValue, -1);

            Log.FileLog.Write("CreateKey " + k, LogType.Hint);
            UserValidateList.Add(k, GetPageValidateRulesList(true, urlTager));
            return k;
        }

        /// <summary>ValuedateKey 的心跳
        /// </summary> 
        /// <returns></returns>
        public static bool Pant()
        {
            return UserValidateList != null;
        }

        /// <summary> 恢复Key
        /// </summary>
        public static void RecoverKey()
        {
            var vKey = HttpContext.Current.Request.Form["__ValidateKey"].ToInt(0);
            UserValidateList[vKey] = TempNowValidateRules;
        }
    }

    /// <summary> 扩展TextFor方法,使其支持数据验证.
    /// </summary>
    public static class ValidateExtentionMethod
    {
        public static Validate Validate(this MvcHtmlString sender)
        {
            return new Validate(htmlString: sender.ToString());
            //check一下validate的写法是否正确
        }
    }

    /*

    /// <summary> 数据验证Key类
    /// </summary>
    public class ValidateKey
    {
        Random rd = new Random((int)DateTime.Now.Ticks);

        /// <summary> 随机生成一个key
        /// </summary>
        /// <returns></returns>
        public int CreateKey()
        {
            while (true)
            {
                var k = rd.Next();
                lock (list)
                {
                    if (!list.ContainsKey(k))
                    {
                        list.Add(k, DateTime.Now);
                        return k;
                    }
                }
            }
        }

        /// <summary> 判断Key 是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(int key)
        {
            return list.ContainsKey(key);
        }

        /// <summary> Remove Key
        /// </summary>
        /// <param name="key"></param>
        public void RemoveKey(int key)
        {
            lock (list)
            {
                list.Remove(key);


                //移除掉过期数据.
                if (list.Count > 8096)
                {
                    var li = list.Where(j => j.Value.AddMinutes(30) < DateTime.Now).Select(j => j.Key).ToArray();
                    var c = li.Count();
                    for (int i = 0; i < c; i++)
                    {
                        list.Remove(li[i]);
                    }
                }
            }
        }

        /// <summary> 用户会话数据
        /// </summary>
        Dictionary<int, DateTime> list = new Dictionary<int, DateTime>();

        public void AddKey(int vKey)
        {
            list[vKey] = DateTime.Now;
        }
    }

    */

}